package com.bsdk.install.device.lockLora.v1.cmd;

import com.alibaba.fastjson2.JSONObject;
import com.bsdk.common.utils.StringUtils;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

/**
 * @projectName: lock
 * @package: com.hlslock.lock.cmd
 * @className: Cmd
 * @author: HansYoung
 * @description: TODO
 * @date: 2023/12/6 14:14
 * @version: 1.0
 */

@NoArgsConstructor
@Getter
public class COMMAND extends Cmd {
    byte[] data = new byte[100];


    // 锁包类型
    private static final byte PACKET_TYPE_SERVER_REQ = (byte) 0x80;// 服务器发给锁的请求
    private static final byte PACKET_TYPE_LOCK_RESP = (byte) 0x86;// 锁应答服务器的响应

    //ping 锁

    //注册锁

    // 远程开锁
    public String unlock() {
        int j = 0;
        return pack(PACKET_TYPE_SERVER_REQ, CMD_REMOTE_UNLOCK_REQ, data, j);
        //return "0202803003B3";
    }
    // 远程关锁
    public String lock() {
        int j = 0;
        return pack(PACKET_TYPE_SERVER_REQ, CMD_REMOTE_LOCK_REQ, data, j);
        //return "0202803003B3";
    }
    //复位锁数据
    public String reset() {
        int j = 0;
        return pack(PACKET_TYPE_SERVER_REQ, CMD_REMOTE_RESET_REQ, data, j);
        //return "0202803003B3";
    }

    //  添加/修改用户密码
    //对于失效用户，这个函数需要重新写一下
    public String addOrModifyUserPassword(boolean admin,String pwType, String pw, Date startTime, Date endTime, int userId) {

        //Date 转换成 231210101000

        int j = 0, i;

        // 管理用户与普通用户
        if (admin) data[j++] = 0x01;
        else data[j++] = 0x00;

        // password
        j = buildPassword(pw, 14, data, j);
        // userId
        j = buildUserId(userId, data, j);
        // hardware ID
        data[j++] = (byte) 0xFF;
        data[j++] = (byte) 0xFF;

        // 开始时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(startTime).substring(2), data, j);
        // 结束时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(endTime).substring(2), data, j);
        // 其他
        for (i = 0; i < 10; i++) data[j++] = (byte) 0xFF;

        return pack(PACKET_TYPE_SERVER_REQ, CMD_ADDPASS_BY_ID_REQ, data, j);
    }
    public String addOrModifyUserPassword(boolean admin,String pwType, String pw, Date startTime, Date endTime, int userId, JSONObject cycle,int times) {

        //Date 转换成 231210101000
        Byte cmd_type=null;
        int j = 0, i,pos;
        String mode,modeStart,modeEnd,check;
        byte[] validMask;
        int hour,minute,mode_b;
        String tmp1,tmp2;
        // 管理用户与普通用户
        if (admin) data[j++] = 0x01;
        else data[j++] = 0x00;

        if(pwType.equals("password"))
        {
            // password
            cmd_type = CMD_ADDPASS_BY_ID_REQ;
            j = buildPassword(pw, 14, data, j);
        }
        else if(pwType.equals("card"))
        {
            cmd_type = CMD_ADDCARD_BY_ID_REQ;
            j = buildCard(pw, 14, data, j);
        }
        else if(pwType.equals("idcard"))
        {

            j = buildIdCard(pw, 14, data, j);
        }


        // userId
        j = buildUserId(userId, data, j);
        // hardware ID
        data[j++] = (byte) 0xFF;
        data[j++] = (byte) 0xFF;

        // 开始时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(startTime).substring(2), data, j);
        // 结束时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(endTime).substring(2), data, j);
        // 其他
       // if(cycle.isEmpty())
        if(cycle== null) {
            data[j++] = (byte) 0xFF;//循环方式：0--不循环  1---按天  2----按周  3----按月
            for (i = 0; i < 8; i++) data[j++] = (byte) 0xFF;
            //for (i = 0; i < 10; i++) data[j++] = (byte) 0xFF;
        }
        else
        {
            mode = cycle.getString("mode");
            modeStart = cycle.getString("modeStart");
            modeEnd =cycle.getString("modeEnd");
            //check = cycle.getString("check");

//            Long  a = Long.parseLong(check,2);
//            data[j++] = Long.toHexString(a);
            if (Objects.equals(mode, "day")) {
                mode_b = 0x01;
                check = "";
            }
            else if (Objects.equals(mode, "week")){
                check = StringUtils.join(cycle.getJSONArray("week"), "");
                mode_b = 0x02;
            }
            else if(Objects.equals(mode, "month")){
                check = StringUtils.join(cycle.getJSONArray("month"), "");
                mode_b = 0x03;
            }
            else{
                mode_b = 0xFF;
                check = "";
            }
            //循环模式
            data[j++] = (byte) mode_b;
            //二进制转16进制
            //月转换
            //天、周、月循环
            validMask = Valid_toBytes(check, (byte)mode_b);
            for(i = 0;i<4;i++)data[j++] = validMask[i];
            //时限
            pos = modeStart.indexOf(':');
            if(pos>1) {
                hour = Integer.parseInt(modeStart.substring(0, pos), 10);
                minute = Integer.parseInt(modeStart.substring(pos+1,modeStart.length()), 10);
                //tmp1 = modeStart.substring(0, pos);
                //tmp2 = modeStart.substring(pos+1,modeStart.length());
                //hour = Integer.parseInt(tmp1);
                //minute = Integer.parseInt(modeStart.substring(pos+1), 16);
                data[j++] = (byte)hour;//起始有效时段：时
                data[j++] = (byte)minute;//起始有效时段：分
                hour = Integer.parseInt(modeEnd.substring(0, pos), 10);
                minute = Integer.parseInt(modeEnd.substring(pos+1,modeStart.length()), 10);
                data[j++] = (byte)hour;//结束有效时段：时
                data[j++] = (byte)minute;//结束有效时段：分

            }
            else
            {
                for(i = 0;i<4;i++)data[j++] =(byte) 0xFF;
            }


        }
        if(times<1)
        {
            data[j++] = (byte) 0xFF;
        }
        else{
            data[j++] = (byte) times;
        }
        return pack(PACKET_TYPE_SERVER_REQ, cmd_type, data, j);
    }
    public String addUserPassword(boolean admin,String pwType, String pw, Date startTime, Date endTime) {

        //Date 转换成 231210101000
        Byte cmd_type=null;
        int j = 0, i,pos;
        String mode,modeStart,modeEnd,check;
        byte[] validMask;
        int hour,minute,mode_b;
        String tmp1,tmp2;
        // 管理用户与普通用户
        if (admin) data[j++] = 0x01;
        else data[j++] = 0x00;

        if(pwType.equals("password"))
        {
            // password
            cmd_type = CMD_ADDPASS_BY_ID_REQ;
            j = buildPassword(pw, 14, data, j);
        }
        else if(pwType.equals("card"))
        {
            cmd_type = CMD_ADDCARD_BY_ID_REQ;
            j = buildCard(pw, 14, data, j);
        }
        else if(pwType.equals("idcard"))
        {

            j = buildIdCard(pw, 14, data, j);
        }



        // 开始时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(startTime).substring(2), data, j);
        // 结束时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(endTime).substring(2), data, j);

        return pack(PACKET_TYPE_SERVER_REQ, cmd_type, data, j);
    }

    
    // 通过用户编号冻结、解冻用户 0x3c
    public String frozenOrUnFrozoneByUserId(boolean isFrozen, int userId) {
        int j = 0;
        if (isFrozen) data[j++] = 0x00;
        else data[j++] = 0x01;
        // 用户ID
        j = buildUserId(userId, data, j);

        return pack(PACKET_TYPE_SERVER_REQ, CMD_DIS_ENABLE_BY_ID_REQ, data, j);
    }

    // 通过ID修改密码    0x42
    public String modifyPasswordByUserId(int userId, String pw) {
        int j = 0;

        // userId
        j = buildUserId(userId, data, j);
        // password
        j = buildPassword(pw, 14, data, j);

        return pack(PACKET_TYPE_SERVER_REQ, CMD_MODIPASS_BY_ID_REQ, data, j);
    }

    // 下发临时密码的key    0x3D
    public String addAdminPassword(String pw) {

        int j = buildPassword(pw, 12, data, 0);

        return pack(PACKET_TYPE_SERVER_REQ, CMD_ADD_ADMIN_PASSWORD_REQ, data, j);
    }


    // 通过ID修改有效期　　0x41
    public String modifierValidTime(int userId, Date startTime, Date endTime) {
        int j = 0;

        // 用户ID
        j = buildUserId(userId, data, j);
        // 开始时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(startTime).substring(2), data, j);
        // 结束时间
        j = buildTime(new SimpleDateFormat("yyyyMMddHHmmss").format(endTime).substring(2), data, j);

        return pack(PACKET_TYPE_SERVER_REQ, CMD_MODIVALID_BY_ID_REQ, data, j);
    }

    // 通过用户ID删除用户
    public String DeleteUserById(int userId) {
        int j = 0;

        // 用户ID
        j = buildUserId(userId, data, j);
        return pack(PACKET_TYPE_SERVER_REQ, CMD_DELPASS_BY_ID_REQ, data, j);
    }

    // 下发校准时间  0x3A
    public String adjustTime() {
        int j = 0;

        // 下发当前的时间
        LocalDateTime localDateTime = LocalDateTime.now().plusSeconds(5);
        data[j++] = (byte) (localDateTime.getYear() - 2000);// 23年
        data[j++] = (byte) localDateTime.getMonthValue();// 12月
        data[j++] = (byte) localDateTime.getDayOfMonth();// 10日
        data[j++] = (byte) localDateTime.getHour();// 17点
        data[j++] = (byte) localDateTime.getMinute();// 25分
        data[j++] = (byte) localDateTime.getSecond();// 00秒

        return pack(PACKET_TYPE_SERVER_REQ, CMD_ADJUST_TIME_REQ, data, j);
    }

    /**
     * 下载指纹数据
     * @param Face_data 100字节，不足补0
     * @param packed_id  6包
     * @return
     */
    public String Face_data_ACK(String Face_data,int packed_id) {
        int j = 0;
        int i;
        int str_len;
        byte [] tmp = new byte[120];

        data[j++] = (byte) packed_id;//packed_id
        str_len = Face_data.length();

        if(str_len!=200)return "FFFF"; //需要写一下
        tmp = toBytes(Face_data);
        for (i = 0; i < 100; i ++) data[j++] = tmp[i];
        return pack(PACKET_TYPE_SERVER_REQ, CMD_DOWN_FINGER_DATA, data, j);

    }

    public String Register_face(boolean admin,int crc,int len) {
        int j = 0;
        if(admin) data[j++] = 0x01;
        else data[j++] = 0x00;
        if(len!=600)return "FFFF"; //需要写一下
        data[j++] = (byte)(len/0x100);
        data[j++] = (byte)(len%0x100);
        data[j++] = (byte)(crc/0x100);
        data[j++] = (byte)(crc%0x100);
        return pack(PACKET_TYPE_SERVER_REQ, CMD_ADD_FACE_USER, data, j);
    }
    /**
     * 生成离线密码
     *
     * @param startTime 密码生效时间， 时间戳 秒，不能小于当前时间前50分钟的时间戳
     * @param duration  可用时长 分钟[1,60]，如果不是5的倍数就往前推，比如：43，变成 45
     * @param key       生成临时密码的Key
     * @return 成功： 8位密码， 不成功：null
     */
    public String generalOffLinePassword(Date startTime, Integer duration, String key) {

        long startTimeStamp = startTime.getTime() / 1000;

        byte[] factor = {0x55, 0x55, 0x55};
        byte[] data = {0, 0, 0, 0};
        // default 1 hour
        int fiveCount = 12;
        int password = 0;
        int pwMaxLen = 12;
        byte[] pw = toBytes(buildPassword(key, pwMaxLen));

        // 生效时间不能小于当前时间前50分钟
        if (startTimeStamp < System.currentTimeMillis() / 1000 - 5 * 60 * 10) return null;

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String startDateString = dateFormat.format(new Date(startTimeStamp * 1000));

        try {
            Date date2019 = dateFormat.parse("2019-01-01");
            Date startTimeZeroDate = dateFormat.parse(startDateString);

            // 生效日期距离 2019-01-01 的天数
            long days = (startTimeZeroDate.getTime() - date2019.getTime()) / 1000 / 60 / 60 / 24;
            // 生效时间距离生效日期0点0时0分的分钟数，也就是现在是当天的第几分钟
            long minus = (startTimeStamp - startTimeZeroDate.getTime() / 1000) / 60;

            int t = (int) Math.random() * 3 + 1;

            if (duration % 5 > 0) {
                fiveCount = duration / 5 + (5 - duration % 5);
            } else {
                fiveCount = duration / 5;
            }

            data[0] = (byte) (days & 0xFF);
            data[1] = (byte) (minus & 0xFF);
            data[2] = (byte) (fiveCount * 0x10 + minus / 0x100);
            data[3] = (byte) (t);

            // encrpty
            for (int i = 0; i < 3; i++)
                data[i] = (byte) ((data[i] ^ factor[i]) ^ (pw[2 * i] + pw[2 * i + 1]));

            // small
            password = Byte.toUnsignedInt(data[0]) + Byte.toUnsignedInt(data[1]) * 0x100 +
                    Byte.toUnsignedInt(data[2]) * 0x10000 + Byte.toUnsignedInt(data[3]) * 0x1000000;

        } catch (ParseException e) {
            e.printStackTrace();
        }

        return String.valueOf(password);
    }

    /**
     * 构建命令
     *
     * @param type
     * @param cmd
     * @param data
     * @param len
     * @return
     */
    private String pack(byte type, byte cmd, byte[] data, int len) {
        int j = 0, i;
        byte[] buf = new byte[100];
        StringBuilder stringBuilder = new StringBuilder();

        buf[j++] = 0x02;
        buf[j++] = (byte) (len + 2);
        buf[j++] = type;
        buf[j++] = cmd;
        for (i = 0; i < len; i++) {
            buf[j++] = data[i];
        }
        buf[j++] = 0x03;
        buf[j++] = check(buf, j);

        for (i = 0; i < j; i++) {
            stringBuilder.append(String.format("%02X", buf[i]));
        }
        return stringBuilder.toString();
    }


    //一下是与LORA模块的通讯，协议是不一样的
    public String pinglock() {
        return "02010078ADFF";
    }
    public String registlock() {
        return "02010077ECFF";
    }
    //  FROM GateWay:{ "fMac":"0050C262C21E","cMac":"0000e0357feb","type":"0220","time":"230105121009"}
    public String registlock(String gwmac) {
        int j = 0;
        int i;
        int len;
        byte [] mac = new byte[12];
        j = 0;
        len = gwmac.length();
        if(len!=12)return "FFFF"; //需要写一下
        mac = toBytes(gwmac);
        data[j++] = CHILD_SET_MASTER_ADDR_CMD;//注册模块查询
        for(i = 0;i<6;i++)data[j++] = mac[i];
        return pack_crc(data, j);
    }

    public String req_registlock() {
        int j = 0;
    //    private static final byte  CHILD_SET_MASTER_ADDR_CMD = (byte) 0x7E; //注册模块
     //   private static final byte  CHILD_REQ_MASTER_ADDR_CMD = (byte) 0x7F; //查询模块注册

        j = 0;
        data[j++] = CHILD_REQ_MASTER_ADDR_CMD;//注册模块查询
        return pack_crc(data, j);
    }
    private String pack_crc(byte[] data, int len) {
        int j = 0, i;
        byte[] buf = new byte[100];
        StringBuilder stringBuilder = new StringBuilder();

        buf[j++] = 0x02;
        buf[j++] =  (byte)(len % 0x100);//len的低位
        buf[j++] = (byte)(len / 0x100);//len的高位
        for (i = 0; i < len; i++) {
            buf[j++] = data[i];
        }
        buf[j++] = check_crc(buf, j-1);
        buf[j++] = (byte)0xFF;
        for (i = 0; i < j; i++) {
            stringBuilder.append(String.format("%02X", buf[i]));
        }
        return stringBuilder.toString();
    }
    /*
       指纹和人脸 CRC的算法，校验和
     */
    public int CMD_GenCRC(byte[] cpRecBuf, int len)
    {
        int i;
        int result = 0;

        for (i = 0; i < len; i++)
        {
            result += (cpRecBuf[i] & 0xff);
        }
        result = result % 0x10000;//16位
        return result;
    }

}